using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Diagram.Model;
using Algorithms.Numerical;
using Base;


namespace PetriDiagram.Model
{
    [Serializable]
    public class PetriNetModel : EntityManager
    {
        //private List<Place> places;
        //private List<Transition> transitions;

        // Jak niby pola "places" i "transitions" maja byc uzupelniane nowymi polami i tranzycjami??!!

        public PetriNetModel()
        {
            //places = new List<Place>();
            //transitions = new List<Transition>();
        }

        

        public ReadOnlyCollection<Place> Places
        {
            get
            {
                //return places.AsReadOnly();
                List<Place> places = new List<Place>();
                foreach (Entity e in Entities)
                {
                    if (e is Place)
                        places.Add((Place)e);
                }
                return places.AsReadOnly();
            }
        }

        public ReadOnlyCollection<Transition> Transitions
        {
            get
            {
                //return transitions.AsReadOnly();
                List<Transition> transitions = new List<Transition>();
                foreach (Entity e in Entities)
                {
                    if (e is Transition)
                        transitions.Add((Transition)e);
                }
                return transitions.AsReadOnly();
            }
        }

        public List<PetriNetEntity> GetInputs(Entity entity)
        {
            List<PetriNetEntity> inputs = new List<PetriNetEntity>();

            foreach( Relation relation in Relations )
                if( relation.To == entity )
                    inputs.Add( relation.From as PetriNetEntity );

            return inputs;
        }


        public List<PetriNetEntity> GetOutputs(Entity entity)
        {
            List<PetriNetEntity> outputs = new List<PetriNetEntity>();

            foreach( Relation relation in Relations )
                if( relation.From == entity )
                    outputs.Add( relation.To as PetriNetEntity );

            return outputs;
        }

        public List<PetriNetRelation> GetIncommingConnections(Entity entity)
        {
            List<PetriNetRelation> inputs = new List<PetriNetRelation>();

            foreach( Relation relation in Relations )
                if( relation.To == entity && relation is PetriNetRelation )
                    inputs.Add( relation as PetriNetRelation );

            return inputs;
        }

        public List<PetriNetRelation> GetOutgoingConnections( Entity entity )
        {
            List<PetriNetRelation> outputs = new List<PetriNetRelation>();

            foreach( Relation relation in Relations )
                if( relation.From == entity && relation is PetriNetRelation )
                    outputs.Add( relation as PetriNetRelation );

            return outputs;
        }

        public List<InhibitorArc> GetIncomingInhibitors( Transition trans )
        {
            List<InhibitorArc> outputs = new List<InhibitorArc>();

            foreach( Relation relation in Relations )
                if( relation.To == trans && relation is InhibitorArc )
                    outputs.Add( relation as InhibitorArc );

            return outputs;
        }

        public IntMatrix IncidentionMatrix
        {
            get
            {                
                IntMatrix m = new IntMatrix(Places.Count, Transitions.Count );

                for( int pnum = 0; pnum < Places.Count; pnum++ )
                {
                    Place p = Places[pnum];

                    List<PetriNetRelation> outRels = GetOutgoingConnections(p);
                    foreach (PetriNetRelation orel in outRels )
                    {
                        Transition t = (Transition)orel.To;
                        int tnum = Transitions.IndexOf(t);
                        m[pnum, tnum] -= orel.Weight;                        
                    }
                    List<PetriNetRelation> inRels = GetIncommingConnections(p);
                    foreach (PetriNetRelation irel in inRels)
                    {
                        Transition t = (Transition)irel.From;
                        int tnum = Transitions.IndexOf(t);
                        m[pnum, tnum] += irel.Weight;
                    }
                }
                return m;
            }
        }

        public MarkingVector GetMarkingVector()
            {
            MarkingVector mv = new MarkingVector( Places.Count );
            for( int pnum = 0; pnum < Places.Count; pnum++ )
                {
                Place p = Places[ pnum ];
                mv[ pnum ] = p.Tokens;
                }

            return mv;
            }
    }
}
